<?php
declare (strict_types = 1);

namespace app\controller\admin;

use app\event\AdminActionEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use think\Request;
use app\model\AdminMenu;
use think\facade\Log;
use think\facade\Db;
use app\traits\MyControllerTrait;
use app\validate\admin\AdminMenuValidate;
use think\exception\ValidateException;
use think\facade\Session;
use app\model\AdminPermission;

class AdminMenuController
{
    use MyControllerTrait;

    protected string $uri = '/admin/menu';

    public function index(Request $request)
    {
        $data = [
            'uri'   => $this->uri,
            'title' => $this->getPermissionTitle($this->uri.'/'.__FUNCTION__),
            'menus' => $this->getMenuNav($this->uri.'/'.__FUNCTION__)
        ];
        return view($this->uri.'/'.__FUNCTION__, $data);
    }// index() end

    public function create(Request $request)
    {
        $data = [
            'uri'       => $this->uri,
            'pid'       => AdminMenu::getAllPid(),
            'is_show'   => AdminMenu::FIELDS['is_show'],
            '__token__' => $request->buildToken()
        ];
        return view($this->uri.'/'.__FUNCTION__, $data);
    }// create() end

    public function show(Request $request)
    {
        $title   = $request->get('title/s', '');
        $is_show = $request->get('is_show/s', '');

        $page  = $request->get('page/d', 1);
        $limit = $request->get('limit/d', 10);
        $where = "";
        $raw   = [];

        if (strlen($title) > 0)
        {
            $where       .= " AND title LIKE :title";
            $raw['title'] = "%{$title}%";
        }
        if (strlen($is_show) > 0)
        {
            $where         .= " AND is_show = :is_show";
            $raw['is_show'] = (int)$is_show;
        }

        [$total, $data] = AdminMenu::searchForShow(AdminMenu::class, $where, $raw, $page, $limit);
        foreach ($data as $key => $val){
            $data[$key]['pid']     = AdminMenu::findOrEmpty($val['pid'])->title ?? "顶级菜单";
            $data[$key]['is_show'] = AdminMenu::FIELDS['is_show'][$val['is_show']];
        }
        return json(['code' => 0, 'message' => 'success', 'data' => $data, 'total' => $total]);
    }// show() end

    public function edit(Request $request)
    {
        // admin_menu.id
        $admin_menu_id = $request->get('id/d', 0);
        $admin_menu_id = abs($admin_menu_id);

        $menus = AdminMenu::whereRaw('id = :id', ['id' => $admin_menu_id])->findOrEmpty()->toArray();

        $data = [
            'uri'       => $this->uri,
            'pid'       => AdminMenu::getAllPid(),
            'is_show'   => AdminMenu::FIELDS['is_show'],
            'data'      => $menus,
            '__token__' => $request->buildToken()
        ];
        return view($this->uri.'/'.__FUNCTION__, $data);
    }// edit() end

    public function store(Request $request)
    {
        $pid     = $request->post('pid/d', 0);// admin_menu.pid
        $rank    = $request->post('rank/d', 0);// admin_menu.rank
        $title   = $request->post('title/s', '');// admin_menu.title
        $uri     = $request->post('uri/s', '');// admin_menu.uri
        $is_show = $request->post('is_show/d', 1);// admin_menu.is_show

        // 参数校验
        $check_data = [
            'pid'       => $pid,
            'rank'      => $rank,
            'title'     => $title,
            'uri'       => $uri,
            'is_show'   => $is_show
        ];
        try{
            validate(AdminMenuValidate::class)->check($check_data);
        } catch (ValidateException $validateException) {
            return json([
                'code'      => 0,
                'message'   => $validateException->getError()
            ]);
        }

        $menu = AdminMenu::whereRaw('title = :title', ['title' => $title])->findOrEmpty();
        if ($menu->isExists()) return json(['code' => 0, 'message' => "名称 {$title} 已存在"]);
        // 顶级菜单跳过
        if ($uri !== '#')
        {
            $menu = AdminMenu::whereRaw('uri = :uri', ['uri' => $uri])->findOrEmpty();
            if ($menu->isExists()) return json(['code' => 0, 'message' => "链接 {$uri} 已存在"]);
        }
        if ($request->checkToken('__token__') === false) return json(['code' => 0, 'message' => '页面失效,请刷新页面']);

        AdminMenu::generateLog($pid, $rank, $title, $uri, $is_show);
        // 写入访问权限
        $permission = AdminPermission::whereRaw("title = :title", ['title' => $title])->findOrEmpty();
        if ($permission->isEmpty())
        {
            $title2      = AdminMenu::whereRaw('id = :id', ['id' => $pid])->value('title') ?? "";
            $pid         = (int)AdminPermission::whereRaw('title = :title', ['title' => $title2])->value('id') ?? 0;
            $permission2 = AdminPermission::whereRaw("uri = :uri AND uri <> '#'", ['uri' => $uri])->findOrEmpty();
            if ($permission2->isEmpty()) AdminPermission::generateLog($title, $uri, $pid, AdminPermission::generatePath($pid));
        }

        $data = [
            $this->getPermissionTitle($this->uri.'/'.__FUNCTION__),
            Session::get("admin_user.account"),
            $check_data
        ];
        (new EventDispatcher)->dispatch((new AdminActionEvent($request, $data)), AdminActionEvent::EVENT_NAME);
        return json(['code' => 1, 'message' => '保存成功']);
    }// store() end

    public function update(Request $request)
    {
        $admin_menu_id = $request->put('id/d', 0);// admin_menu.id
        $pid           = $request->put('pid/d', 0);// admin_menu.pid
        $rank          = $request->put('rank/d', 0);// admin_menu.rank
        $title         = $request->put('title/s', '');// admin_menu.title
        $uri           = $request->put('uri/s', '');// admin_menu.uri
        $is_show       = $request->put('is_show/d', 1);// admin_menu.is_show

        // 参数校验
        $check_data = [
            'pid'       => $pid,
            'rank'      => $rank,
            'title'     => $title,
            'uri'       => $uri,
            'is_show'   => $is_show
        ];
        try{
            validate(AdminMenuValidate::class)->check($check_data);
        } catch (ValidateException $validateException) {
            return json([
                'code'      => 0,
                'message'   => $validateException->getError()
            ]);
        }

        if ($admin_menu_id < 34) return json(['code' => 0, 'message' => '禁止更新基础菜单']);

        $menu = AdminMenu::whereRaw('id = :id', ['id' => $admin_menu_id])->findOrEmpty();
        if ($menu->isEmpty()) return json(['code' => 0, 'message' => "菜单不存在"]);

        if ($menu->title !== $title)
        {
            $menu2 = AdminMenu::whereRaw("title = :title", ['title' => $title])->findOrEmpty();
            if ($menu2->isExists()) return json(['code' => 0, 'message' => "名称 {$title} 已存在"]);
        }

        if ($menu->uri !== $uri)
        {
            $menu3 = AdminMenu::whereRaw("uri = :uri", ['uri' => $uri])->findOrEmpty();
            if ($menu3->isExists()) return json(['code' => 0, 'message' => "链接 {$uri} 已存在"]);
        }

        if ($request->checkToken('__token__') === false) return json(['code' => 0, 'message' => '页面失效,请刷新页面']);

        $permission = AdminPermission::whereRaw("title = :title AND uri = :uri", ['title' => $menu->title, 'uri' => $menu->uri])->findOrEmpty();
        if ($permission->isExists())
        {
            $permission->title      = $title;
            $permission->uri        = $uri;
            $permission->updated_at = date('Y-m-d H:i:s');
            $permission->save();
        } else {
            AdminPermission::generateLog($title, $uri, $pid, AdminPermission::generatePath($pid));
        }

        $menu->pid          = $pid;
        $menu->rank         = $rank;
        $menu->title        = $title;
        $menu->uri          = $uri;
        $menu->is_show      = $is_show;
        $menu->updated_at   = date('Y-m-d H:i:s');
        $menu->save();

        $data = [
            $this->getPermissionTitle($this->uri.'/'.__FUNCTION__),
            Session::get("admin_user.account"),
            $menu->toArray()
        ];
        (new EventDispatcher)->dispatch((new AdminActionEvent($request, $data)), AdminActionEvent::EVENT_NAME);
        return json(['code' => 1, 'message' => '保存成功']);
    }// update() end

    public function destroy(Request $request)
    {
        $admin_menu_id = $request->delete('id/d', 0);// $admin_menu.id

        $menu = AdminMenu::whereRaw('id = :id', ['id' => $admin_menu_id])->findOrEmpty();
        if ($menu->isEmpty()) return json(['code' => 0, 'message' => '失败']);
        if ($admin_menu_id < 32) return json(['code' => 0, 'message' => '禁止删除基础菜单']);

        Db::startTrans();
        try {
            $admin_menu_pid = (int)$menu->id;
            $menu->delete();
            // 删除子菜单
            AdminMenu::deleteChildMenu($admin_menu_pid);

            $permission = AdminPermission::whereRaw("title = :title AND uri = :uri", ['title' => $menu->title, 'uri' => $menu->uri])->findOrEmpty();
            if ($permission->isExists()) $permission->delete();

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();

            $message = [
                'function'  => __CLASS__.'->'.__FUNCTION__.'():'.__LINE__,
                'error'     => $e->getMessage()
            ];
            Log::channel('web-controller')->error(json_encode($message, JSON_UNESCAPED_UNICODE));

            return json(['code' => 0, 'message' => '失败']);
        }
        $data = [
            $this->getPermissionTitle($this->uri.'/'.__FUNCTION__),
            Session::get("admin_user.account"),
            $menu->toArray()
        ];
        (new EventDispatcher)->dispatch((new AdminActionEvent($request, $data)), AdminActionEvent::EVENT_NAME);
        return json(['code' => 0, 'message' => '成功']);
    }// destroy() end
}
